﻿using Admin.NET.Application.Entity;
using Admin.NET.Core.Service;
using Microsoft.AspNetCore.Http;
using static Admin.NET.Application.Service.ModbusTcpService.ModbusTcpService;

namespace Admin.NET.Application;

/// <summary>
/// 设备变量值服务
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class DevicePointsValueService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<DevicePointsValue> _devicePointsValueRep;
    private readonly DevicePointsValueHistoryService _devicePointsValueHistoryService;
    private readonly DeiviceTemplateTriggerService _deiviceTemplateTriggerService;
    private readonly DeviceTriggerHistoryService _deviceTriggerHistoryService;
    private readonly SysNoticeService _sysNoticeService;

    public DevicePointsValueService(SqlSugarRepository<DevicePointsValue> devicePointsValueRep, DevicePointsValueHistoryService devicePointsValueHistoryService, DeiviceTemplateTriggerService deiviceTemplateTriggerService, DeviceTriggerHistoryService deviceTriggerHistoryService, SysNoticeService sysNoticeService)
    {
        _devicePointsValueRep = devicePointsValueRep;
        this._devicePointsValueHistoryService = devicePointsValueHistoryService;
        this._deiviceTemplateTriggerService = deiviceTemplateTriggerService;
        this._deviceTriggerHistoryService = deviceTriggerHistoryService;
        this._sysNoticeService = sysNoticeService;
    }

    /// <summary>
    /// 分页查询设备变量值
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Page")]
    [DisplayName("分页查询设备变量值")]
    public async Task<SqlSugarPagedList<DevicePointsValueOutput>> Page(PageDevicePointsValueInput input)
    {
        input.SearchKey = input.SearchKey?.Trim();
        var query = _devicePointsValueRep.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
                u.PonitValue.Contains(input.SearchKey)
            )
            .WhereIF(input.DeviceInfoId > 0, u => u.DeviceInfoId == input.DeviceInfoId)
            .WhereIF(input.DeviceSlaveTemplatePointsId > 0, u => u.DeviceSlaveTemplatePointsId == input.DeviceSlaveTemplatePointsId)
            .WhereIF(!string.IsNullOrWhiteSpace(input.PonitValue), u => u.PonitValue.Contains(input.PonitValue.Trim()))
            //处理外键和TreeSelector相关字段的连接
            .LeftJoin<DeviceInfo>((u, deviceinfoid) => u.DeviceInfoId == deviceinfoid.Id)
            .LeftJoin<DeviceSlaveTemplatePoints>((u, deviceinfoid, deviceslavetemplatepointsid) => u.DeviceSlaveTemplatePointsId == deviceslavetemplatepointsid.Id)
            .Select((u, deviceinfoid, deviceslavetemplatepointsid) => new DevicePointsValueOutput
            {
                Id = u.Id,
                DeviceInfoId = u.DeviceInfoId,
                DeviceInfoIdDeviceName = deviceinfoid.DeviceName,
                DeviceSlaveTemplatePointsId = u.DeviceSlaveTemplatePointsId,
                DeviceSlaveTemplatePointsIdPointName = deviceslavetemplatepointsid.PointName,
                PonitValue = u.PonitValue,
                CreateTime = u.CreateTime,
                UpdateTime = u.UpdateTime,
                CreateUserId = u.CreateUserId,
                CreateUserName = u.CreateUserName,
                UpdateUserId = u.UpdateUserId,
                UpdateUserName = u.UpdateUserName,
                IsDelete = u.IsDelete,
            });
        return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
    }

    /// <summary>
    /// 增加设备变量值
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Add")]
    [DisplayName("增加设备变量值")]
    public async Task<long> Add(AddDevicePointsValueInput input)
    {
        var entity = input.Adapt<DevicePointsValue>();
        await _devicePointsValueRep.InsertAsync(entity);
        return entity.Id;
    }

    /// <summary>
    /// 删除设备变量值
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Delete")]
    [DisplayName("删除设备变量值")]
    public async Task Delete(DeleteDevicePointsValueInput input)
    {
        var entity = await _devicePointsValueRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _devicePointsValueRep.FakeDeleteAsync(entity);   //假删除
        //await _devicePointsValueRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 更新设备变量值
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [ApiDescriptionSettings(Name = "Update")]
    [DisplayName("更新设备变量值")]
    public async Task Update(UpdateDevicePointsValueInput input)
    {
        var entity = input.Adapt<DevicePointsValue>();
        await _devicePointsValueRep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
    }

    /// <summary>
    /// 获取设备变量值
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "Detail")]
    [DisplayName("获取设备变量值")]
    public async Task<DevicePointsValue> Detail([FromQuery] QueryByIdDevicePointsValueInput input)
    {
        return await _devicePointsValueRep.GetFirstAsync(u => u.Id == input.Id);
    }

    /// <summary>
    /// 获取设备变量值列表
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpGet]
    [ApiDescriptionSettings(Name = "List")]
    [DisplayName("获取设备变量值列表")]
    public async Task<List<DevicePointsValueOutput>> List([FromQuery] PageDevicePointsValueInput input)
    {
        return await _devicePointsValueRep.AsQueryable().Select<DevicePointsValueOutput>().ToListAsync();
    }

    /// <summary>
    /// 获取设备ID列表
    /// </summary>
    /// <returns></returns>
    [ApiDescriptionSettings(Name = "DeviceInfoDeviceInfoIdDropdown"), HttpGet]
    [DisplayName("获取设备ID列表")]
    public async Task<dynamic> DeviceInfoDeviceInfoIdDropdown()
    {
        return await _devicePointsValueRep.Context.Queryable<DeviceInfo>()
                .Select(u => new
                {
                    Label = u.DeviceName,
                    Value = u.Id
                }
                ).ToListAsync();
    }

    /// <summary>
    /// 获取变量ID列表
    /// </summary>
    /// <returns></returns>
    [ApiDescriptionSettings(Name = "DeviceSlaveTemplatePointsDeviceSlaveTemplatePointsIdDropdown"), HttpGet]
    [DisplayName("获取变量ID列表")]
    public async Task<dynamic> DeviceSlaveTemplatePointsDeviceSlaveTemplatePointsIdDropdown()
    {
        return await _devicePointsValueRep.Context.Queryable<DeviceSlaveTemplatePoints>()
                .Select(u => new
                {
                    Label = u.PointName,
                    Value = u.Id
                }
                ).ToListAsync();
    }

    /// <summary>
    /// 更新设备上的变量值，同时更新数据库
    /// </summary>
    /// <param name="deviceId"></param>
    /// <param name="point"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public async Task UpdataPointValueByProcess(long deviceId, DeviceSlaveTemplatePoints point, string value, ReadValueType readValueType, string oldValue, DateTime createTime)
    {
        var pointValue = await _devicePointsValueRep.Context.CopyNew().Queryable<DevicePointsValue>()
            .Where(x => x.DeviceInfoId == deviceId && x.DeviceSlaveTemplatePointsId == point.Id)
            .FirstAsync();
        pointValue.PonitValue = point.DataValue;
        pointValue.UpdateTime = createTime;
        await _devicePointsValueRep.Context.CopyNew().Updateable(pointValue).IgnoreColumns().ExecuteCommandAsync();
        //查找这个点的触发器
        var trigger = await _deiviceTemplateTriggerService.DetailByPointId(new QueryByIdDeiviceTemplateTriggerInput { Id = point.Id });
        bool isAlarm = false;
        bool isRecovert = false;
        if (trigger != null)
        {
            //根据触发类型处理数据
            switch (trigger.TriggerCondition)
            {
                case TriggerCondition.SwitchOff:
                    var oldFlag = Convert.ToBoolean(oldValue);
                    var nowFlag = Convert.ToBoolean(value);
                    if (oldFlag == true && nowFlag == false)
                    {
                        isAlarm = true;
                    }
                    else if (oldFlag == false && nowFlag == true)
                    {
                        isRecovert = true;
                    }
                    break;

                case TriggerCondition.SwitchOn:
                    oldFlag = Convert.ToBoolean(oldValue);
                    nowFlag = Convert.ToBoolean(value);
                    if (oldFlag == false && nowFlag == true)
                    {
                        isAlarm = true;
                    }
                    else if (oldFlag == true && nowFlag == false)
                    {
                        isRecovert = true;
                    }
                    break;

                case TriggerCondition.ValueLessThanA:
                    var oldInt = Convert.ToInt16(oldValue);
                    var nowInt = Convert.ToInt16(value);
                    if (nowInt <= trigger.Min && oldInt > trigger.Min)
                    {
                        isAlarm = true;
                    }
                    else if (nowInt > trigger.Min && oldInt <= trigger.Min)
                    {
                        isRecovert = true;
                    }
                    break;

                case TriggerCondition.ValueGreaterThanB:
                    oldInt = Convert.ToInt16(oldValue);
                    nowInt = Convert.ToInt16(value);
                    if (nowInt >= trigger.Max && oldInt < trigger.Max)
                    {
                        isAlarm = true;
                    }
                    else if (oldInt >= trigger.Max && nowInt < trigger.Max)
                    {
                        isRecovert = true;
                    }
                    break;

                case TriggerCondition.ValueBetweenAAndB:
                    oldInt = Convert.ToInt16(oldValue);
                    nowInt = Convert.ToInt16(value);
                    if ((oldInt < trigger.Min || oldInt > trigger.Max) && (nowInt >= trigger.Min && nowInt <= trigger.Max))
                    {
                        isAlarm = true;
                    }
                    else if ((oldInt >= trigger.Min && oldInt <= trigger.Max) && (nowInt < trigger.Min || nowInt > trigger.Max))
                    {
                        isRecovert = true;
                    }
                    break;

                case TriggerCondition.ValueLessThanAOrGreaterThanB:
                    oldInt = Convert.ToInt16(oldValue);
                    nowInt = Convert.ToInt16(value);
                    if ((oldInt >= trigger.Min && oldInt <= trigger.Max) && (nowInt < trigger.Min || nowInt > trigger.Max))
                    {
                        isAlarm = true;
                    }
                    else if ((oldInt < trigger.Min || oldInt > trigger.Max) && (nowInt >= trigger.Min && nowInt <= trigger.Max))
                    {
                        isRecovert = true;
                    }
                    break;

                case TriggerCondition.ValueEqualToA:
                    oldInt = Convert.ToInt16(oldValue);
                    nowInt = Convert.ToInt16(value);
                    if (oldInt != trigger.Min && nowInt == trigger.Min)
                    {
                        isAlarm = true;
                    }
                    else if (oldInt == trigger.Min && nowInt != trigger.Min)
                    {
                        isRecovert = true;
                    }
                    break;

                default:
                    break;
            }
            if (isAlarm)
            {
                await _deviceTriggerHistoryService.Add(new AddDeviceTriggerHistoryInput
                {
                    DeviceId = deviceId,
                    PointId = point.Id,
                    TriggerId = trigger.Id,
                    TriggerStatus = TriggerStatus.Alarm,
                    TriggerIsProcess = TriggerIsProcess.UnProcess,
                    DataValue = value,
                });
                await _sysNoticeService.PublicMessage(trigger.CustomContentAlarm, MessageTypeEnum.Error);
            }
            else if (isRecovert)
            {
                await _deviceTriggerHistoryService.Add(new AddDeviceTriggerHistoryInput
                {
                    DeviceId = deviceId,
                    PointId = point.Id,
                    TriggerId = trigger.Id,
                    TriggerStatus = TriggerStatus.Normal,
                    TriggerIsProcess = TriggerIsProcess.NoNeedProcess,
                    DataValue = value,
                });
                await _sysNoticeService.PublicMessage(trigger.CustomContentNormal, MessageTypeEnum.Success);
            }
        }
        if (point.Store == StoreType.ChangeStorage && oldValue == value)
        {
            return;
        }

        await _devicePointsValueHistoryService.Add(new AddDevicePointsValueHistoryInput
        {
            DeviceInfoId = deviceId,
            DeviceSlaveTemplatePointsId = point.Id,
            PonitValue = value,
            ReadValueType = readValueType,
            CreateTime = createTime
        });
    }
}